package com.gitee.wsl.ext.number

import com.gitee.wsl.math.Math
import kotlin.math.pow

// ---
/** Returns the next power of two. Returns the specified value if the value is already a power of two.  */
fun Math.nextPowerOfTwo(value: Int): Int {
    var value1 = value
    if (value1 == 0) return 1
    value1--
    value1 = value1 or value1 shr 1
    value1 = value1 or value1 shr 2
    value1 = value1 or value1 shr 4
    value1 = value1 or value1 shr 8
    value1 = value1 or value1 shr 16
    return value1 + 1
}

fun Math.isPowerOfTwo(value: Int): Boolean {
    return value != 0 && value and value - 1 == 0
}

infix fun Int.pow(exponent: Int) = toFloat().pow(exponent).toInt()
infix fun Int.pow(exponent: Float) = toFloat().pow(exponent).toInt()

infix fun Float.pow(exponent: Int) = pow(exponent)
infix fun Float.pow(exponent: Float) = pow(exponent)

/** Returns the next power of two of [this] */
val Int.nextPowerOfTwo: Int get() {
    var v = this
    v--
    v = v or (v shr 1)
    v = v or (v shr 2)
    v = v or (v shr 4)
    v = v or (v shr 8)
    v = v or (v shr 16)
    v++
    return v
}
/** Checks if [this] value is power of two */
val Int.isPowerOfTwo: Boolean get() = this.nextPowerOfTwo == this

/** Returns the previous power of two of [this] */
val Int.prevPowerOfTwo: Int get() = if (isPowerOfTwo) this else (nextPowerOfTwo ushr 1)

fun Long.pow(exponent: Long): Long = toDouble().pow(exponent.toDouble()).toLong()

fun Long.pow(exponent: Int): Long = toDouble().pow(exponent.toDouble()).toLong()


/**
 * Gets a power of 2 that is less than or equal to the given integer
 *
 * Examples: -1->1，0->1，1->1，2->2，3->2，4->4，5->4，6->4，7->4，8->8，9->8
 *
 */
fun Math.floorRoundPow2(number: Int): Int {
    return number.takeHighestOneBit().coerceAtLeast(1)
}

/**
 * Gets a power of 2 that is greater than or equal to the given integer
 *
 * Examples: -1->1，0->1，1->1，2->2，3->4，4->4，5->8，6->8，7->8，8->8，9->16
 *
 * Copy from Java 17 'HashMap.tableSizeFor()' method
 *
 */
fun Math.ceilRoundPow2(number: Int): Int {
    val n = -1 ushr (number - 1).countLeadingZeroBits()
    return if (n < 0) 1 else if (n >= 1073741824) 1073741824 else n + 1
}

/**
 * Squares this number.
 *
 * @return the result of squaring this number.
 */
fun Double.pow() = pow(2.0)

 infix fun Short.pow(exp: Short) = toInt() pow exp.toInt()
 infix fun Byte.pow(exp: Byte)= toInt() pow exp.toInt()